<template>
  <div class="page">
    <div class="player-info" :class="{ 'fullscreen': state.fullscreen }">
      <div v-if="!state.fullscreen" class="backto-course">
        <div class="operation">
          <div class="icon"><LeftOutlined :style="{ fontSize: '24px' }" /></div>
          <div class="text" @click="navigateTo('/course/index', {id: `${state.courseDetail.id}`})">返回课程详情</div>
        </div>
        <div class="space"></div>
      </div>

      <!-- 播放器 -->
      <div id="container" class="player-container"></div>

      <!-- 视频信息 -->
      <div v-if="!state.fullscreen" class="video-info">
        <div class="video-title">{{ state.currentVideo.title }}</div>
        <div class="course-info">
          <div class="section-info">共{{ state.courseDetail.videoNum }}讲  更新到{{ state.courseDetail.curVideoNum }}讲</div>
          <div class="tag-list">
            <a-tag :color="state.courseDetail.curVideoNum>=state.courseDetail.videoNum ? '' : 'error'">{{ state.courseDetail.curVideoNum>=state.courseDetail.videoNum ? '已完结' : '连载中' }}</a-tag>
          </div>
        </div>
      </div>
    </div>

    <!-- 目录（显示条件：非全屏时；或全屏且显示目录时） -->
    <div v-if="!state.fullscreen" class="player-catalog">
      <div class="list-title">目录</div>
      <div class="list-data">
        <CourseCatalog :items="state.videoList" :selectedKeys="[state.currentVideo.seq]" theme="light-small">
          <template #title="{ item }">
            <div class="title" :title="item.title">
              <a @click="async () => await loadBySeq(item.seq)">{{ item.title }}</a>
            </div>
          </template>
        </CourseCatalog>
      </div>
    </div>

    <a-modal v-model:open="state.showDialog" title="提示" @ok="handleDialogNext" @cancel="handleDialogCancle" style="width: 420px;">
      <template #footer>
        <a-button key="next" type="primary" @click="handleDialogNext">播放下一个视频</a-button>
        <a-button key="repeat" @click="handleDialogRepeat">重新学习</a-button>
        <a-button key="cancel" @click="handleDialogCancle">取消</a-button>
      </template>
      <p>当前视频已学习完成，要重新学习吗?</p>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { reactive, onBeforeMount, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
import { message } from 'ant-design-vue';
import { useRoute } from 'vue-router';
import { LeftOutlined } from '@ant-design/icons-vue';
import Aliplayer from "aliyun-aliplayer";
import "aliyun-aliplayer/build/skins/default/aliplayer-min.css";
import type { PlayInfo } from "@/models/player";
import usePlayerStore from "@/stores/player";
import useAppStore from "@/stores/app";
import { useNavigation } from "@utils/navigation";
import appConfig from '@/config';
import { miscApi } from "@/services";
import "@/assets/js/aliplayercomponents-1.1.1.min.js"
import "@/assets/js/myplaylistcomponent-1.0.1.min.js"
import CourseCatalog from '@/components/CourseCatalog.vue';

const { navigateTo } = useNavigation();
const route = useRoute();
const storeApp = useAppStore();
const storePlayer = usePlayerStore();

const state = reactive({
  fullscreen: false,
  showCatalogInFullscreen: false,
  courseId: "",
  courseDetail: {},
  videoList: [],
  currentVideoIndex: 0,
  currentVideo: {} as PlayInfo,
  reportInterval: null,
  player: null,

  showDialog: false
});

// 初始化播放器
const initPlayer = async (videoInfo: PlayInfo) => {
  let options = {
    id: "container",
    width: "100%",
    height: "100%",
    cover: videoInfo.coverURL, // 视频封面
    autoplay: false, // 自动播放
    isLive: false,
    rePlay: false,
    playsinline: true,
    preload: true,
    language: "zh-cn",
    controlBarVisibility: "hover",
    useH5Prism: true,
    license: {
      domain: appConfig.aliPlayerLicenseDomain, // 申请 License 时填写的域名
      key: appConfig.aliPlayerLicenseKey // 申请成功后，在控制台可以看到 License Key
    },
    skinLayout: [
      { name: "bigPlayButton", align: "cc" },
      { name: "controlBar", align: "blabs", x: 0, y: 0, children: [
          { name: "progress", align: "blabs", x: 0, y: 44 },
          { name: "playButton", align: "tl", x: 15, y: 12 },
          { name: "timeDisplay", align: "tl", x: 10, y: 7 },
          { name: "fullScreenButton", align: "tr", x: 10, y: 12 }
        ]
      }
    ],
    components: [{
      name: 'QualityComponent',
      type: (window as any).AliPlayerComponent.QualityComponent,
      args: [function(definition,desc) {
        console.log(definition + '-----' + desc)
      }]
    },{
      name: 'MyPlaylistComponent',
      type: (window as any).AliPlayerComponent.MyPlaylistComponent,
      args: [state.videoList, state.currentVideoIndex],
    }]
  };

  // 免费视频
  if (videoInfo.isFree === "1") {
    options["source"] = getSources(videoInfo);
    console.log("options[source] = ", options["source"]);
  }
  // 加密视频
  else {
    options["vid"] = videoInfo.vid;
    options["playauth"] = videoInfo.playauth;
    options["encryptType"] = 1;
  }

  // 更多使用方法请参考接入文档：https://help.aliyun.com/zh/vod/developer-reference/integration
  state.player = new Aliplayer(
    options,
    (player: typeof Aliplayer) => {
      console.log('播放器创建成功')

      player && player.trigger("showControlBar", { currentIndex: state.currentVideoIndex })

      // 若已学习完成则尝试暂停并询问是否重新学习
      if (isFinished(state.currentVideo)) {
        try {
          player.pause();
        } catch (error) {
          console.warn("播放器暂停操作出现异常：", error);
        }

        state.showDialog = true;
      } else {
        // 播放器播放时上报播放进度
        playAndReport();
      }

      // 播放下一个视频
      player.on("ended", async () => {
        // 获取视频总时长，取视频长度和视频信息中长度的最大值（两者存在差异）
        const videoLength = Math.max(player.getDuration(), parseInt(state.currentVideo.duration));
        // 播放结束时上报播放进度（总时长）
        const courseId = '' + state.currentVideo.courseId;
        const seq = '' + (state.currentVideoIndex + 1);
        await storePlayer.reportProgress(courseId, seq, videoLength);

        // 关闭上报定时器
        if (state.reportInterval) {
          clearInterval(state.reportInterval);
        }

        let index = state.currentVideo.seq || 0;
        // 若是最后一个视频，则不切换
        if (index === state.videoList.length - 1) {
          return;
        }
        // 不是最后一个视频，则播放下一个视频
        let nextVideoDetailInfo = state.videoList[index + 1];
        if (nextVideoDetailInfo) {
          update(getPlayInfo(index+1));
        }
      });

      // 监听sourceloaded事件，查询视频的分辨率，调用分辨率组件并调用setCurrentQuality方法来设置分辨率
      player.on('sourceloaded', function(params) {
        var paramData = params.paramData
        var desc = paramData.desc
        var definition = paramData.definition
        player.getComponent('QualityComponent').setCurrentQuality(desc, definition)
      })

      // 全屏点击视频监听播放列表变化
      player.on('plugin-myplaylist-click-video', async (event) => {
        // console.log("plugin-myplaylist-click-video event: ", event)
        await loadBySeq(event.paramData.clickedIndex)
      })

      // 全屏切换视频监听播放列表变化
      player.on('plugin-myplaylist-change', (event) => {
        console.log("plugin-myplaylist-change event: ", event)
      })

      // 进入全屏
      player.on('requestFullScreen', function(params) {
        // // 缓存控制条和目录HTML
        // const domControls = document.querySelector('.player-controls')
        // if (domControls) {
        //   localStorage.setItem("controlsHTML", domControls.innerHTML)
        // }
        // const domCatalog = document.querySelector('.player-catalog')
        // if (domCatalog) {
        //   localStorage.setItem("catalogHTML", domCatalog.innerHTML)
        // }

        state.fullscreen = true;
        state.showCatalogInFullscreen = false;

        console.log("fullscreenService.getIsFullScreen() = ", player.fullscreenService.getIsFullScreen())
      })

      // 退出全屏
      player.on('cancelFullScreen', function(params) {
        // const domControls = document.querySelector('.player-controls')
        // if (domControls) domControls.remove()
        // const domCatalog = document.querySelector('.player-catalog')
        // if (domCatalog) domCatalog.remove()

        state.fullscreen = false;
        state.showCatalogInFullscreen = false;

        console.log("fullscreenService.getIsFullScreen() = ", player.fullscreenService.getIsFullScreen())
      })
    },
  );
};

//点击右侧列表视频切换
const update = async (videoInfo: PlayInfo) => {
  // 若不是免费的，则请求新的播放授权
  if (videoInfo.isFree !== "1") {
    if (videoInfo?.vid) {
      await storePlayer.getPlayAuth(videoInfo.vid);
    }
    // 更新播放授权信息
    if (storePlayer.playAuth) {
      videoInfo.playauth = storePlayer.playAuth;
    }
  }

  // 查询并设置上次播放进度
  let courseId = '' + videoInfo.courseId;
  let seq = '' + (videoInfo.seq + 1);
  let playSecond = await storePlayer.queryProgress(courseId, seq);
  videoInfo.playSecond = playSecond || 0;

  // 保存课程最新播放章节
  storePlayer.setCourseLastSeq(courseId, (videoInfo?.seq || 0));

  // 销毁当前播放器
  if (state.player) {
    state.player.dispose();
  }

  // 创建新的播放器
  await initPlayer(videoInfo);
};

const getTitle = (videoTitle: string): string => {
  let title = videoTitle.split('、');
  return title.length > 1 ? title[1] : title[0];
}
// 获取当前播放信息
const getCurrentPlayInfo = () : PlayInfo => {
  return getPlayInfo(state.currentVideoIndex);
}
// 从视频详情中获取播放信息
const getPlayInfo = (seq: number) : PlayInfo => {
  // 获取播放视频详情
  let videoDetailInfo = state.videoList[seq];

  return {
    courseId: videoDetailInfo.courseId,
    seq: seq,
    videoId: videoDetailInfo.pkId,
    title: videoDetailInfo.videoTitle,
    description: videoDetailInfo.videoDsc,
    isFree: videoDetailInfo.isFree,
    source: videoDetailInfo.aliPubUrl,
    coverURL: videoDetailInfo.aliCoverUrl,
    resolution: videoDetailInfo.videoResolution,
    duration: videoDetailInfo.aliLength || videoDetailInfo.videoLength, // 优先使用aliLength
    vid: videoDetailInfo.aliVid,
    playauth: videoDetailInfo.playAuth,

    playSecond: 0,
  } as PlayInfo;
}

const getVideoList = (videoList) => {
  let chapterIndex = 0;
  let lessonIndex = 0;

  videoList = videoList || [];
  videoList.forEach(video => {
    if (video.isDir && video.isDir == 1) {
      chapterIndex ++;
      video.videoTitle = '第' + chapterIndex + '章　' + getTitle(video.videoTitle);
    } else {
      lessonIndex ++;
      video.videoTitle = '第' + lessonIndex + '讲　' + getTitle(video.videoTitle);
    }
  });
  return videoList;
}

const playAndReport = async () => {
  try {
    // 跳到上次播放的位置
    state.player?.seek(state.currentVideo?.playSecond || 0);

    // 开始播放
    state.player?.play();
  } catch (error) {
    console.warn("播放器播放操作出现异常：", error);
  }

  // 定时上报播放进度（间隔5s）
  if (state.reportInterval) {
    clearInterval(state.reportInterval);
  }
  let courseId = '' + state.currentVideo.courseId;
  let seq = '' + (state.currentVideoIndex + 1);
  state.reportInterval = setInterval(async () => {
    let playSecond = parseInt(state.player?.getCurrentTime()); 
    await storePlayer.reportProgress(courseId, seq, playSecond);
  }, 5000);
}

const resolutionMap =  {
  "270": "OD",
  "360": "FD",
  "540": "LD",
  "720": "SD",
  "1080": "HD",
  "2160": "2K",
  "4320": "4K"
}
const getSources = function (videoInfo: PlayInfo) {
  // console.log("getSources videoInfo = ", videoInfo);
  let sourceTag = videoInfo.resolution ? resolutionMap[videoInfo.resolution] : "SD";
  sourceTag = sourceTag ? sourceTag : "SD";
  const sources = {};
  sources[sourceTag] = videoInfo.source;
  return JSON.stringify(sources);
}

const isFinished = function (videoInfo: PlayInfo) {
  const videoLength = videoInfo.duration ? parseInt(videoInfo.duration) : 0;
  return videoInfo.playSecond >= videoLength;
}

const updateVideoProgress = (index: number, playSecond: number) => {
  if (!(state.videoList && state.videoList.length > 0)) {
    return;
  }
  
  if (!(index >= 0 && index < state.videoList.length)) {
    return;
  }
  
  state.videoList[index].playSecond = playSecond || 0;
}

const getParam = (key: string) => {
  let v = route.query[key] || '';
  return (typeof(v) == "string") ? v : ("" + (v[0] || 0));
}

const loadBySeq = async (videoIndex: number) => {
  if (state.currentVideoIndex === videoIndex) return

  state.currentVideoIndex = videoIndex
  state.currentVideo = getCurrentPlayInfo();
  state.showCatalogInFullscreen = false

  // 若不是免费的，则请求新的播放授权
  if (state.currentVideo.isFree !== "1") {
    if (state.currentVideo?.vid) {
      await storePlayer.getPlayAuth(state.currentVideo.vid);
    }
    // 更新播放授权信息
    if (storePlayer.playAuth) {
      state.currentVideo.playauth = storePlayer.playAuth;
    }
  }

  // 查询并设置上次播放进度
  let courseId = '' + state.currentVideo.courseId;
  let seq = '' + ((state.currentVideo?.seq || 0) + 1);
  let playSecond = await storePlayer.queryProgress(courseId, seq);
  state.currentVideo.playSecond = playSecond || 0;

  location.replace(`/#/player/index?courseId=${state.courseId}&seq=${videoIndex}`)
  await update(getCurrentPlayInfo())
}

onBeforeMount(async () => {
  storeApp.startLoading();

  // 获取课程ID
  state.courseId = getParam("courseId");
  console.log("player course id: ", state.courseId);
  if (!state.courseId) {
    message.error('播放异常，获取不到课程id信息');
    return false;
  }

  // 当前播放视频序号
  let index = 0;
  let seq = route.query.seq;
  console.log("player video seq: ", seq, typeof seq);
  // 若不存在seq参数
  if (typeof(seq) == "undefined") {
    // 继续学习，从本地存储获取最后学习章节
    let lastSeq = storePlayer.getCourseLastSeq(state.courseId);

    // 本地存储没有记录，从视频列表中获取第一个视频
    if (lastSeq != null) {
      try {
        index = Number(lastSeq);
      } catch (error) {
        index = 0;
      }
    } else {
      index = 0;
    }
  } else {
    try {
      index = Number(seq);
    } catch (error) {
      index = 0;
    }
  }
  state.currentVideoIndex = index;
});

onMounted(async () => {
  // 请求课程详情
  await storePlayer.getCourseDetail(state.courseId);
  state.courseDetail = storePlayer.courseDetail;
  state.videoList = getVideoList(storePlayer.courseDetail?.videoList);
  state.currentVideo = getCurrentPlayInfo();

  // 若课程进度为0%，则加入我的课程
  if (!storePlayer.courseProgress || storePlayer.courseProgress=="0%") {
    await storePlayer.joinCourse(state.courseId);
  }

  // 上报页面访问记录
  await miscApi.traceViewPage("/player/index", state.courseId, state.currentVideoIndex);
  
  storeApp.endLoading();

  // 更新并播放视频
  await update(state.currentVideo);
});

onBeforeUnmount(() => {
  // 清除定时器
  if (state.reportInterval) {
    clearInterval(state.reportInterval);
  }

  // 销毁当前播放器
  if (state.player) {
    state.player.dispose();
  }
});

const handleDialogNext = () => {
  // 关闭上报定时器
  if (state.reportInterval) {
    clearInterval(state.reportInterval);
  }

  let index = state.currentVideo.seq || 0;
  // 若是最后一个视频，则不切换
  if (index === state.videoList.length - 1) {
    return;
  }
  // 不是最后一个视频，则播放下一个视频
  let nextVideoDetailInfo = state.videoList[index + 1];
  if (nextVideoDetailInfo) {
    update(getPlayInfo(index+1));
  } else {

  }
  
  state.showDialog = false;
}
const handleDialogRepeat = async () => {
  // 重置视频播放进度
  state.currentVideo.playSecond = 0;
  // 上报课程章节进度
  const courseId = '' + state.currentVideo.courseId;
  const seq = '' + (state.currentVideo.seq + 1);
  await storePlayer.reportProgress(courseId, seq, state.currentVideo.playSecond);
  // 更新视频播放进度(本地存储)
  updateVideoProgress(state.currentVideo.seq, state.currentVideo.playSecond);

  // 播放器播放时上报播放进度
  playAndReport();

  state.showDialog = false;
}
const handleDialogCancle = () => {
  state.showDialog = false;
}

watch(() => route.query, loadCourseData, { immediate: true })

async function loadCourseData() {
  const courseId = route.query.courseId
  const seq = parseInt(route.query.seq || 1)
  
  console.log("courseId: %s, seq: %s", courseId, seq)
}
</script>

<style lang="less" scoped>
.page {
  width: 100%;
  height: 100vh;
  overflow: hidden;
  background: @white-bg;
  display: flex;
  flex-direction: row;

  .player-info {
    width: calc(100% - 520px);
    display: flex;
    flex-direction: column;
    padding: 30px;

    .backto-course {
      display: flex;
      flex-direction: row;
      align-items: center;

      .operation {
        width: 130px;
        height: 30px;
        line-height: 30px;
        display: flex;
        flex-direction: row;
        align-items: center;
        cursor: pointer;

        .icon {
          width: 24px;
          height: 24px;
        }

        .text {
          height: 16px;
          line-height: 16px;
          font-size: 16px;
          font-weight: 500;
          color: @font-grey;
        }
      }
      
      .space {
        flex: 1;
      }
    }

    .player-container {
      width: 100%;
      flex: 1;
      background-color: #000;
      margin-top: 20px;
      position: relative;
    }

    .video-title {
      height: 24px;
      line-height: 24px;
      font-size: 24px;
      font-weight: 500;
      color: @font-black;
      margin-top: 30px;
    }

    .course-info {
      margin-top: 20px;
      display: flex;
      flex-direction: row;
      align-items: center;

      .section-info {
        height: 16px;
        line-height: 16px;
        font-size: 16px;
        font-weight: 400;
        color: @font-grey-light;
      }

      .tag-list {
        margin-left: 20px;
      }
    }

    &.fullscreen {
      widows: 100%;
      height: 100%;

      :deep(.player-container) {
        width: 100%;
        height: 100%;

        .fullscreen-controls {
          width: 100%;
          height: 150px;
          color: @white;
          background: linear-gradient( 180deg, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0) 100%);

          position: absolute;
          top: 0px;
          left: 0px;
          z-index: 11000;
          opacity: 1;
          transition: opacity 0.3s ease;

          display: flex;
          flex-direction: row;
          align-items: center;
          justify-content: flex-end;
          gap: 10px;
          padding: 40px 50px 80px 50px;

          &.hidden {
            opacity: 0;
            pointer-events: none;
          }
          
          .course-title {
            height: 30px;
            line-height: 30px;
            font-size: 20px;
            font-weight: 500;
            text-align: right;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
          }

          .show-catalog-icon {
            width: 30px;
            height: 30px;
          }
        }
        
        .fullscreen-catalog {
          width: 520px;
          height: 100%;
          background: rgba(0,0,0,0.8);

          position: absolute;
          top: 0;
          right: 0;
          z-index: 12000;
          box-shadow: -2px 0 10px rgba(0, 0, 0, 0.2);
          transform: translateX(100%);
          transition: transform 0.3s ease;

          &.show {
            transform: translateX(0);
          }

          .list-title {
            height: 60px;
            font-size: 16px;
            font-weight: 500;
            color: @white;
            padding: 30px 16px 14px 16px;
          }

          .list-data {
            height: calc(100% - 60px);
            overflow-y: auto;
            padding: 0 16px;
          }
        }
      }

      :deep(.course-catalog) {
        background: transparent;

        .catalog-list {
          .catalog-list-title {
            background: @white;
            opacity: 0.4;
          }
          :deep(.catalog-item) {
            background: transparent;
            border-color: @font-grey-disable;

            .title {
              color: @white;
            }
          }
        }
      }
    }
  }

  .player-catalog {
    width: 520px;
    height: 100%;
    background-color: @white;

    .list-title {
      height: 60px;
      font-size: 16px;
      font-weight: 500;
      color: @font-black;
      padding: 30px 16px 14px 16px;
    }

    .list-data {
      height: calc(100% - 60px);
      overflow-y: auto;
      padding: 0 16px;
    }
  }

  :deep(.prism-player) {
    .prism-controlbar {
      .prism-controlbar-bg {
        height: 44px;
        background: rgba(0, 0, 0, .8);
      }
      .prism-progress .prism-progress-played {
        background-color: @text-link-color;
      }
    }
    
    &.prism-fullscreen {
      z-index: 10001;
    }
  }
}
</style>